package main;

import jade.content.Concept;
import jade.content.ContentElement;
import jade.content.lang.Codec;
import jade.content.lang.sl.SLCodec;
import jade.content.onto.Ontology;
import jade.content.onto.basic.Action;
import jade.core.AID;
import jade.core.behaviours.CyclicBehaviour;
import jade.lang.acl.ACLMessage;
import jade.util.leap.ArrayList;
import jade.util.leap.HashMap;
import jade.util.leap.Iterator;
import ontology.EmploymentLawOntology;
import ontology.UMCourtLOntology;
import ontology.actions.employmentlaw.GetCompleteInfo;
import ontology.actions.employmentlaw.GetUtilities;
import ontology.actions.general.AddNewTime;
import ontology.actions.general.GetSimilarCases;
import ontology.actions.general.GetSimilarities;
import ontology.actions.general.PreSelect;
import ontology.actions.general.ReturnCompleteInfo;
import ontology.actions.general.ReturnList;
import ontology.actions.general.ReturnSimilarities;
import ontology.actions.general.ReturnUtilities;
import ontology.concepts.employmentlaw.Case;
import ontology.concepts.employmentlaw.ComputeCompleteInfoTask;
import ontology.concepts.general.ComputeSimilarityTask;
import ontology.concepts.general.ComputeUtilityTask;
import classes.UMCourtAgent;

public class CoordinatorL extends UMCourtAgent {
	private Codec codec = new SLCodec();
	private Ontology ontology = EmploymentLawOntology.getInstance();
	private HashMap tasks = new HashMap();
	private HashMap treeTask = new HashMap();
	private long sgcitime = 0;

	protected void setup() {
		System.out.println(getDate() + ": " + this.getLocalName()
				+ " agent is now running...");
		registerAgent((String) getArguments()[0]);

		// Register language and ontology
		getContentManager().registerLanguage(codec);
		getContentManager().registerOntology(ontology);

		this.addBehaviour(new receiveBehaviour());
	}

	class receiveBehaviour extends CyclicBehaviour {
		@Override
		public void action() {
			ACLMessage msg = receive();
			if (msg == null) {
				block();
				return;
			}

			try {
				myprintln(msg.toString());
				ContentElement content = getContentManager()
						.extractContent(msg);
				Concept action = ((Action) content).getAction();

				switch (msg.getPerformative()) {
				case (ACLMessage.INFORM):
					if (action instanceof ReturnList) {

						myprintln("Received results from pre-selection of task: "
								+ msg.getConversationId());
						ComputeSimilarityTask t = (ComputeSimilarityTask) tasks
								.get(msg.getConversationId());
						t.setPhase(t.getPhase() + 1);
						tasks.remove(msg.getConversationId());
						tasks.put(msg.getConversationId(), t);
						processTask(t, msg);
					}
					if (action instanceof ReturnSimilarities) {
						myprintln("Received results from computing similarity of task: "
								+ msg.getConversationId());
						ComputeSimilarityTask t = (ComputeSimilarityTask) tasks
								.get(msg.getConversationId());
						t.setPhase(t.getPhase() + 1);
						tasks.remove(msg.getConversationId());
						tasks.put(msg.getConversationId(), t);
						processTask(t, msg);
					}
					if (action instanceof ReturnUtilities) {
						myprintln("Received results from computing utilities of task: "+ msg.getConversationId());
						ComputeUtilityTask t = (ComputeUtilityTask) tasks.get(msg.getConversationId());
						t.setPhase(t.getPhase() + 1);
						tasks.remove(msg.getConversationId());
						tasks.put(msg.getConversationId(), t);
						processTask(t, msg);
					}
					break;
				case (ACLMessage.REQUEST):
					if (action instanceof GetSimilarCases) {
						// Begin a new task for computing the similar cases
						content = getContentManager().extractContent(msg);
						GetSimilarCases gsc = (GetSimilarCases) ((Action) content)
								.getAction();

						myprintln("Starting a new Similarity task: "
								+ msg.getConversationId());
						ComputeSimilarityTask t = new ComputeSimilarityTask();
						t.setPhase(UMCourtLOntology.PSELECT);
						t.setConversationID(msg.getConversationId());
						t.setOriginalCase(gsc.getNewcase1());
						t.setRequestingAgent(msg.getSender());

						tasks.put(msg.getConversationId(), t);
						processTask(t, msg);
					}
					if (action instanceof GetUtilities) {
						// Begin a new task for computing the utilities
						content = getContentManager().extractContent(msg);
						GetUtilities gu = (GetUtilities) ((Action) content)
								.getAction();

						myprintln("Starting a new Utilities task: "
								+ msg.getConversationId());
						ComputeUtilityTask t = new ComputeUtilityTask();
						t.setConversationID(msg.getConversationId());
						t.setIds(gu.getIds());
						t.setRequestingAgent(msg.getSender());
						t.setPhase(UMCourtLOntology.GUTILITIES);

						tasks.put(msg.getConversationId(), t);
						processTask(t, msg);
					}
					if (action instanceof GetCompleteInfo) {
						// Begin a new task for computing all the info
						content = getContentManager().extractContent(msg);
						GetCompleteInfo gci = (GetCompleteInfo) ((Action) content)
								.getAction();

						myprintln("Starting a new GetCompleteInfo task: "
								+ msg.getConversationId());
						sgcitime = System.currentTimeMillis();
						ComputeCompleteInfoTask t = new ComputeCompleteInfoTask();
						t.setConversationID(msg.getConversationId());

						t.setOriginalCase(gci.getNewcase1());
						t.setDayWage(gci.getDayWage());
						t.setHourWage(gci.getHourWage());
						t.setMonthWage(gci.getMonthWage());
						t.setNightWork(gci.getNightWork());
						t.setSupplementaryWork(gci.getSupplementaryWork());
						t.setAntiquity(gci.getAntiquity());
						t.setRequestingAgent(msg.getSender());
						t.setPhase(UMCourtLOntology.PSELECT);
						tasks.put(msg.getConversationId(), t);
						processTask(t, msg);
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	private void processTask(Object t, ACLMessage msg) {
		if (t.getClass().equals(ComputeSimilarityTask.class)) {
			ComputeSimilarityTask task = (ComputeSimilarityTask) t;
			switch (task.getPhase()) {
			case (UMCourtLOntology.PSELECT):
				myprintln("Requesting pre-selection of cases for task "
						+ task.getConversationID());
				ontology.actions.general.PreSelect ps = new ontology.actions.general.PreSelect();
				ps.setNewCase(task.getOriginalCase());
				//ps.setMethod("ar");
				ps.setMethod("tr");

				ACLMessage reply = new ACLMessage(ACLMessage.REQUEST);
				reply.setLanguage(codec.getName());
				reply.setOntology(ontology.getName());
				reply.setConversationId(task.getConversationID());

				try {
					getContentManager().fillContent(reply,
							new Action(aids.PRESELECT, ps));
					reply.addReceiver(aids.PRESELECT);
					send(reply);
				} catch (Exception ex) {
					ex.printStackTrace();
				}
				break;
			case (UMCourtLOntology.GSIMILARITY):
				myprintln("Requesting computation of similarities for task "
						+ task.getConversationID());

				try {
					ContentElement content = getContentManager()
							.extractContent(msg);
					ReturnList rl = (ReturnList) ((Action) content).getAction();

					GetSimilarities gs = new GetSimilarities();
					gs.setCases((ArrayList) rl.getList());
					gs.setNewC(task.getOriginalCase());
					//gs.setMethod("cs");
					gs.setMethod("nn");

					reply = new ACLMessage(ACLMessage.REQUEST);
					reply.setLanguage(codec.getName());
					reply.setOntology(ontology.getName());
					reply.setConversationId(task.getConversationID());

					getContentManager().fillContent(reply,
							new Action(aids.NEARESTNEIGHBOUR, gs));
					reply.addReceiver(aids.NEARESTNEIGHBOUR);
					send(reply);
				} catch (Exception e) {
					e.printStackTrace();
				}
				break;
			case (UMCourtLOntology.RSIMILARITY):
				try {
					myprintln("Returning result of Get Similarity Request");
					ContentElement content = getContentManager()
							.extractContent(msg);
					ReturnSimilarities rs = (ReturnSimilarities) ((Action) content)
							.getAction();

					AID receiver = ((ComputeSimilarityTask) tasks.get(msg
							.getConversationId())).getRequestingAgent();

					// Check in the tree if this is a sub-task
					Iterator it = treeTask.keySet().iterator();
					Boolean isSubTask = false;
					while (it.hasNext()) {
						String parent = (String) it.next();
						String child = msg.getConversationId();

						if (((String) treeTask.get(parent)).equals(child)) {
							isSubTask = true;

							// end get similarity task
							myprintln("Ending sub task " + child);
							tasks.remove(child);

							ComputeCompleteInfoTask cit = (ComputeCompleteInfoTask) tasks
									.get(parent);
							cit.setCases(rs.getCaseList());
							cit.setSimilarities(rs.getSimilarities());
							ArrayList cases = rs.getCaseList();
							ArrayList ids = new ArrayList();
							for (int i = 0; i < cases.size(); i++)
								ids.add(((Case) cases.get(i)).getID());
							cit.setIds(ids);

							myprintln("Updating task " + parent);
							cit.setPhase(UMCourtLOntology.RSIMILARITY);

							// save time in database
							sendNewTime("gci", sgcitime);

							processTask(cit, msg);
						}
					}
					if (!isSubTask) {
						// forward the message to the agent that requested the
						// computation of similarity
						msg.removeReceiver((AID) msg.getAllReceiver().next());
						msg.addReceiver(receiver);
						myprintln("Ending task " + msg.getConversationId());
						myprintln("Sending results to agent "
								+ receiver.getName());
						send(msg);
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
				break;
			}
		}
		if (t.getClass().equals(ComputeUtilityTask.class)) {
			ComputeUtilityTask task = (ComputeUtilityTask) t;
			switch (task.getPhase()) {
			case (UMCourtLOntology.GUTILITIES): // ask the utilities agent for
												// the result
				myprintln("Requesting computation of utilities for task "
						+ msg.getConversationId());
				ACLMessage forward = (ACLMessage) msg.clone();
				forward.setSender(this.getAID());
				forward.removeReceiver(this.getAID());
				forward.addReceiver(aids.UTILITY);
				send(forward);
				break;
			case (UMCourtLOntology.RUTILITIES): // forward results to original
												// agent
				try {
					ContentElement content = getContentManager()
							.extractContent(msg);
					ReturnUtilities ru = (ReturnUtilities) ((Action) content)
							.getAction();

					ArrayList ids = ru.getIds();
					ArrayList utilities = ru.getUtilities();
					ArrayList outcomes = ru.getOutcomes();

					AID receiver = ((ComputeUtilityTask) tasks.get(msg
							.getConversationId())).getRequestingAgent();

					// Check in the tree if this is a sub-task
					Iterator it = treeTask.keySet().iterator();
					Boolean isSubTask = false;
					while (it.hasNext()) {
						String parent = (String) it.next();
						String child = msg.getConversationId();

						if (((String) treeTask.get(parent)).equals(child)) {
							isSubTask = true;

							// end get utility task
							myprintln("Ending sub task " + child);
							tasks.remove(child);

							myprintln("Updating task " + parent);
							ComputeCompleteInfoTask cit = (ComputeCompleteInfoTask) tasks
									.get(parent);

							cit.setUtilities(utilities);
							cit.setOutcomes(outcomes);
							cit.setPhase(UMCourtLOntology.RUTILITIES);

							processTask(cit, msg);
						}
					}
					if (!isSubTask) {
						// forward result to the agent that requested utility
						myprintln("Ending task " + msg.getConversationId());
						tasks.remove(msg.getConversationId());
						forward = (ACLMessage) msg.clone();
						forward.setSender(this.getAID());
						forward.removeReceiver(this.getAID());
						forward.addReceiver(task.getRequestingAgent());
						myprintln("Sending results to agent "
								+ receiver.getName());
						send(forward);
					}

				} catch (Exception e) {
					e.printStackTrace();
				}
				break;
			}
		}
		if (t.getClass().equals(ComputeCompleteInfoTask.class)) {
			ComputeCompleteInfoTask task = (ComputeCompleteInfoTask) t;
			switch (task.getPhase()) {
			case (UMCourtLOntology.PSELECT): // Create a sub GetSimilarCases
												// task
				GetSimilarCases gsc = new GetSimilarCases();
				gsc.setNewcase1(task.getOriginalCase());

				ACLMessage m = new ACLMessage(ACLMessage.REQUEST);
				m.setLanguage(codec.getName());
				m.setOntology(ontology.getName());
				m.setConversationId("" + System.currentTimeMillis());

				// this is a complex task, initialize a HashMap for the subtasks
				// <parent convID, child convID>
				treeTask.put(task.getConversationID(), m.getConversationId());

				try {
					getContentManager().fillContent(m,
							new Action(this.getAID(), gsc));
					m.addReceiver(this.getAID());
					send(m);
				} catch (Exception e) {
					e.printStackTrace();
				}
				break;
			case (UMCourtLOntology.GSIMILARITY):
				break;
			case (UMCourtLOntology.RSIMILARITY):
				// Start new sub task
				GetUtilities gu = new GetUtilities();
				gu.setAntiquity(task.getAntiquity());
				gu.setDayWage(task.getDayWage());
				gu.setHourWage(task.getHourWage());
				ArrayList cases = task.getCases();
				ArrayList ids = new ArrayList();
				for (int i = 0; i < cases.size(); i++)
					ids.add(((Case) cases.get(i)).getID());
				gu.setIds(ids);
				gu.setMonthWage(task.getMonthWage());
				gu.setNightWork(task.getNightWork());
				gu.setSupplementaryWork(task.getSupplementaryWork());

				ACLMessage request = new ACLMessage(ACLMessage.REQUEST);
				request.setLanguage(codec.getName());
				request.setOntology(ontology.getName());
				request.setConversationId("" + System.currentTimeMillis());

				// this is a complex task, initialize a HashMap for the subtasks
				// <parent convID, child convID>
				treeTask.put(task.getConversationID(),
						request.getConversationId());

				try {
					getContentManager().fillContent(request,
							new Action(this.getAID(), gu));
					request.addReceiver(this.getAID());
					send(request);
				} catch (Exception e) {
					e.printStackTrace();
				}
				break;
			case (UMCourtLOntology.GUTILITIES):
				break;
			case (UMCourtLOntology.RUTILITIES):
				AID receiver = task.getRequestingAgent();

				// remove from tree
				myprintln("Ending task " + task.getConversationID());
				tasks.remove(task.getConversationID());
				treeTask.remove(task.getConversationID());

				// send complete information
				ReturnCompleteInfo rci = new ReturnCompleteInfo();
				rci.setIds(task.getIds());
				rci.setSimilarities(task.getSimilarities());
				rci.setUtilities(task.getUtilities());
				rci.setOutcomes(task.getOutcomes());

				ACLMessage reply = new ACLMessage(ACLMessage.INFORM);
				reply.addReceiver(task.getRequestingAgent());
				reply.setLanguage(codec.getName());
				reply.setOntology(ontology.getName());
				reply.setConversationId(task.getConversationID());

				try {
					getContentManager().fillContent(reply,
							new Action(receiver, rci));
					send(reply);
				} catch (Exception e) {
					e.printStackTrace();
				}
				break;
			}
		}

	}
}
